﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Data.SQLite;
using System.Data.Entity.Core.Common.CommandTrees.ExpressionBuilder;
using System.Security.Cryptography;
using System.Collections;
using static System.Windows.Forms.VisualStyles.VisualStyleElement.TrackBar;
using System.Reflection.Emit;
using System.Text.RegularExpressions;
using System.Xml.Linq;

namespace BYUStock
{
    public partial class PickStock : Form
    {
        public PickStock()
        {
            InitializeComponent();
            InitTables();
            DbTest();
        }

        DataTable Stocks;
        DataTable Groups;
        DataTable GroupDetails;
        void InitTables()
        {
            Stocks = new DataTable();
            Stocks.Columns.Add("code");
            Stocks.Columns.Add("name");
            Stocks.Columns.Add("exchange");
            Stocks.Columns.Add("kind");
            Stocks.Columns.Add("JG");
            Stocks.Columns.Add("SZ");
            Stocks.Columns.Add("SYL");
            Stocks.Columns.Add("SJL");
            Stocks.Columns.Add("SXL");
            Stocks.Columns.Add("GXL");
            Stocks.Columns.Add("FZL");
            Stocks.Columns.Add("XJL");
            Stocks.Columns.Add("MLL");
            Stocks.Columns.Add("PXL");
            Stocks.Columns.Add("ZYS");
            Stocks.Columns.Add("JLR");
            Groups = new DataTable();
            Groups.Columns.Add("id");
            Groups.Columns.Add("name");
            Groups.Columns.Add("kind");
            GroupDetails = new DataTable();
            GroupDetails.Columns.Add("uid");
            GroupDetails.Columns.Add("group_id");
            GroupDetails.Columns.Add("kind");
            GroupDetails.Columns.Add("stock_code");
            GroupDetails.Columns.Add("stock_name");
        }

        void DbTest()
        {
            var connStr = "Data Source =" + AppDomain.CurrentDomain.BaseDirectory + "stock_base.db;";
            var conn = new SQLiteConnection(connStr);
            conn.Open();
            ///股票
            var sql1 = "select * from StockBaseInfo";
            var cmd1 = new SQLiteCommand(sql1);
            cmd1.Connection = conn;
            var reader1 = cmd1.ExecuteReader();
            while (reader1.Read())
            {
                var code = reader1.GetString(0);
                var name = reader1.GetString(1);
                var exchange = reader1.GetString(2);
                var kind = reader1.GetInt32(3);
                //4,5是日期
                var JG = reader1.GetString(6);
                var SZ = reader1.GetString(7);
                var SYL = reader1.GetString(8);
                var SJL = reader1.GetString(9);
                var SXL = reader1.GetString(10);
                var GXL = reader1.GetString(11);
                var FZL = reader1.GetString(12);
                var XJL = reader1.GetString(13);
                var MLL = reader1.GetString(14);
                var PXL = reader1.GetString(15);
                var ZYS = reader1.GetString(16);
                var JLR = reader1.GetString(17);
                Stocks.Rows.Add(code, name, exchange, kind,
                                JG,
                                SZ,
                                SYL,
                                SJL,
                                SXL,
                                GXL,
                                FZL,
                                XJL,
                                MLL,
                                PXL,
                                ZYS,
                                JLR);
            }
            grid_Stock_Result.DataSource = Stocks;
            grid_Stock_Result.Columns[0].HeaderText = "代码";
            grid_Stock_Result.Columns[1].HeaderText = "名称";
            grid_Stock_Result.Columns[2].Visible = false;//HeaderText = "归属";
            grid_Stock_Result.Columns[3].Visible = false;//HeaderText = "类型";
            grid_Stock_Result.Columns[4].Visible = false;//HeaderText = "价格";
            grid_Stock_Result.Columns[5].Visible = false;//HeaderText = "市值";
            grid_Stock_Result.Columns[6].Visible = false;//HeaderText = "市盈率";
            grid_Stock_Result.Columns[7].Visible = false;//HeaderText = "市净率";
            grid_Stock_Result.Columns[8].Visible = false;//HeaderText = "市销率";
            grid_Stock_Result.Columns[9].Visible = false;//HeaderText = "股息率";
            grid_Stock_Result.Columns[10].Visible = false;//HeaderText = "负债率";
            grid_Stock_Result.Columns[11].Visible = false;//HeaderText = "现金流";
            grid_Stock_Result.Columns[12].Visible = false;//HeaderText = "毛利率";
            grid_Stock_Result.Columns[13].Visible = false;//HeaderText = "派息率";
            grid_Stock_Result.Columns[14].Visible = false;//HeaderText = "总营收";
            grid_Stock_Result.Columns[15].Visible = false;//HeaderText = "净利润";
            ///板块
            var sql2 = "select * from GroupKind";
            var cmd2 = new SQLiteCommand(sql2);
            cmd2.Connection = conn;
            var reader2 = cmd2.ExecuteReader();
            while (reader2.Read())
            {
                var id = reader2.GetString(0);
                var name = reader2.GetString(1);
                var kind = reader2.GetString(2);
                Groups.Rows.Add(id, name, kind);
            }
            grid_Groups.DataSource = Groups;
            grid_Groups.Columns[0].HeaderText = "ID";
            grid_Groups.Columns[1].HeaderText = "名称";
            grid_Groups.Columns[2].HeaderText = "类型";
            ///板块
            var sql3 = "select * from StockGroup";
            var cmd3 = new SQLiteCommand(sql3);
            cmd3.Connection = conn;
            var reader3 = cmd3.ExecuteReader();
            while (reader3.Read())
            {
                var uid = reader3["ID"];
                var groupId = reader3["GroupID"];
                var kind = reader3["Kind"];
                var stockCode = reader3["Code"];
                var stockName = reader3["StockName"];
                GroupDetails.Rows.Add(uid, groupId, kind, stockCode, stockName);
            }
        }

        private void PickStock_Load(object sender, EventArgs e)
        {
            string localPath = AppDomain.CurrentDomain.BaseDirectory + $@"BK\";
            string date = "" + DateTime.Now.Year + DateTime.Now.Month.ToString().PadLeft(2, '0') + DateTime.Now.Day.ToString().PadLeft(2, '0');
            string localFile = $@"{localPath}{date}.html";
            string err;
            var updateResult = Global.RefreshBkList();
            LoadLocalBks(localFile, out err);
            BkPages = Bks.Count / BkPageCapacity + 1;
            ShowBkPage(0);
        }

        void Clear()
        {
            grid_Stock_Result.DataSource
                = grid_Groups.DataSource
                = grid_Group_Details.DataSource = GroupDetailCache
                = null;
            ShowGroupDetails(null);
        }
        void Reset()
        {
            ShowStocks(Stocks);
        }
        void ShowStocks(DataTable stocks)
        {
            grid_Stock_Result.DataSource = stocks;
            var groups = SearchGroupsOfStockGridRow(0);
            grid_Groups.DataSource = groups;
            var groupDetails = SearchGroupDetailsOfGroupGridRow(0);
            grid_Group_Details.DataSource = GroupDetailCache = groupDetails;
            ShowGroupDetails(groupDetails);
        }


        DataTable GroupDetailCache = null;
        class GroupDetailComparer : IEqualityComparer<DataRow>
        {
            public bool Equals(DataRow stock1, DataRow stock2)
            {
                return stock1["stock_code"].ToString() == (stock2["stock_code"].ToString());
            }

            public int GetHashCode(DataRow stock)
            {
                return stock["stock_code"].ToString().GetHashCode();
            }
        }
        private void dgv_Groups_CellMouseClick(object sender, DataGridViewCellMouseEventArgs e)
        {
            ///查板块成分
            var selectedRows = grid_Groups.SelectedRows;
            if (selectedRows == null || selectedRows.Count == 0)
            {
                grid_Group_Details.DataSource = null;
                return;
            }
            SelectedBkIds_Grid.Clear();
            foreach (DataGridViewRow gridRow in selectedRows)
            {
                var bkId = gridRow.Cells["id"].Value.ToString();
                SelectedBkIds_Grid.Add(bkId);
            }
            //var groupIds_grid = selectedRows.Cast<DataGridViewRow>().Select(row => row.Cells["id"].Value.ToString());
            //var groupIds_btn = SelectedBkBtns.Select(_btn => _btn.Tag.ToString());
            //if (groupIds_grid == null || groupIds_btn == null)
            //{
            //    ShowResultStocks(null);
            //}
            //else
            //{
            //    var result = SearchStocksCrossGroups(groupIds_grid.Intersect(groupIds_btn));
            //    ShowResultStocks(result);
            //}
            var result = SearchStocksCrossGroups(SelectedBkIds_Btn.Union(SelectedBkIds_Grid));
            ShowResultStocks(result);
        }
        void ShowResultStocks(IEnumerable<DataRow> result, float syl_min = float.MinValue, float syl_max = float.MaxValue, float sz_min = float.MinValue, float sz_max = float.MaxValue)
        {
            if (result == null || result.Count() == 0)
            {
                GroupDetailCache = null;
                grid_Group_Details.DataSource = null;
                gbx_Group_Detail.Text = $"成分股";
            }
            else
            {
                var stockCodes = result.Select(row => row["stock_code"].ToString());
                var stocks = SelectStocksOfCodes(stockCodes);
                IEnumerable<DataRow> filterStocks = stocks.Rows.Cast<DataRow>();
                if (ckx_SYL.Checked)
                {
                    syl_min = float.Parse(tbx_SYL_min.Text);
                    syl_max = float.Parse(tbx_SYL_max.Text);
                    if (syl_min > int.MinValue && filterStocks != null)
                    {
                        filterStocks = filterStocks.Where(row => string.IsNullOrEmpty(row["SYL"].ToString()) ? false : float.Parse(row["SYL"].ToString()) >= syl_min);
                    }
                    if (syl_min < int.MaxValue && filterStocks != null)
                    {
                        filterStocks = filterStocks.Where(row => string.IsNullOrEmpty(row["SYL"].ToString()) ? false : float.Parse(row["SYL"].ToString()) <= syl_max);
                    }
                }
                if (ckx_SZ.Checked)
                {
                    sz_min = float.Parse(tbx_SZ_min.Text);
                    sz_max = float.Parse(tbx_SZ_max.Text);
                    if (sz_min > int.MinValue && filterStocks != null)
                    {
                        filterStocks = filterStocks.Where(row => string.IsNullOrEmpty(row["SZ"].ToString()) ? false : float.Parse(row["SZ"].ToString().Replace("亿", "").Trim()) >= sz_min);
                    }
                    if (sz_max < int.MaxValue && filterStocks != null)
                    {
                        filterStocks = filterStocks.Where(row => string.IsNullOrEmpty(row["SZ"].ToString()) ? false : float.Parse(row["SZ"].ToString().Replace("亿", "").Trim()) <= sz_max);
                    }
                }
                if (filterStocks.Count() == 0)
                {
                    grid_Stocks_Final.DataSource = null;
                    return;
                }
                grid_Stocks_Final.DataSource = filterStocks.CopyToDataTable();
                grid_Stocks_Final.Columns[0].HeaderText = "代码";
                grid_Stocks_Final.Columns[1].HeaderText = "名称";
                grid_Stocks_Final.Columns[2].HeaderText = "归属";
                grid_Stocks_Final.Columns[3].HeaderText = "类型";
                grid_Stocks_Final.Columns[4].HeaderText = "价格";
                grid_Stocks_Final.Columns[5].HeaderText = "市值";
                grid_Stocks_Final.Columns[6].HeaderText = "市盈率";
                grid_Stocks_Final.Columns[7].HeaderText = "市净率";
                grid_Stocks_Final.Columns[8].HeaderText = "市销率";
                grid_Stocks_Final.Columns[9].HeaderText = "股息率";
                grid_Stocks_Final.Columns[10].HeaderText = "负债率";
                grid_Stocks_Final.Columns[11].HeaderText = "现金流";
                grid_Stocks_Final.Columns[12].HeaderText = "毛利率";
                grid_Stocks_Final.Columns[13].HeaderText = "派息率";
                grid_Stocks_Final.Columns[14].HeaderText = "总营收";
                grid_Stocks_Final.Columns[15].HeaderText = "净利润";
                grid_Stocks_Final.Columns[2].Visible = false;
                grid_Stocks_Final.Columns[3].Visible = false;

                GroupDetailCache = result.CopyToDataTable();
                grid_Group_Details.DataSource = GroupDetailCache;
                gbx_Group_Detail.Text = $"成分股({result.Count()})";
                grid_Group_Details.Columns[0].Visible = grid_Group_Details.Columns[1].Visible = grid_Group_Details.Columns[2].Visible = false;
            }
        }

        DataTable SelectStocksOfCodes(IEnumerable<string> codes)
        {
            if (codes == null || codes.Count() == 0) return null;
            return Stocks.Rows.Cast<DataRow>().Where(row => codes.Contains(row["code"].ToString())).CopyToDataTable();
        }

        private void tbx_Group_Detail_TextChanged(object sender, EventArgs e)
        {
            var key = tbx_Search_Stocks_of_Bk.Text.Trim().ToLower();
            if (string.IsNullOrEmpty(key))
            {
                ShowGroupDetails(GroupDetailCache);
                return;
            }
            ///查股票
            var result = GroupDetailCache.Rows.Cast<DataRow>()
                                              .Where(row => row["stock_code"].ToString().ToLower().Contains(key) ||
                                                     row["stock_name"].ToString().ToLower().Contains(key));
            ShowGroupDetails(result == null || result.Count() == 0 ? null : result.CopyToDataTable());
        }



        DataTable EmptyTable = null;

        DataTable SearchGroupsOfStockGridRow(int rowIndex)
        {
            if (grid_Stock_Result.Rows.Count == 0 || rowIndex < 0 || rowIndex >= grid_Stock_Result.RowCount) return EmptyTable;
            var stockCode = grid_Stock_Result.Rows[rowIndex].Cells["code"].Value.ToString();
            return SearchGroupsOfStock(stockCode);
        }
        DataTable SearchStocks(string key)
        {
            var result = Stocks.Rows.Cast<DataRow>()
                               .Where(row => row["name"].ToString().ToLower().Contains(key) ||
                                      row["code"].ToString().ToLower().Contains(key));
            if (result == null || result.Count() == 0) return EmptyTable;
            return result.CopyToDataTable();
        }
        DataTable SearchGroupsOfStock(string stockCode)
        {
            var result = GroupDetails.Rows.Cast<DataRow>()
                                          .Where(row => row["stock_code"].ToString().ToLower() == stockCode);
            if (result == null || result.Count() == 0) return EmptyTable;
            var groupIds = result.Select(row => row["group_id"].ToString());
            if (groupIds == null || groupIds.Count() == 0) return EmptyTable;
            return SelectGroups(groupIds.ToArray());
        }
        DataTable SearchGroups(params string[] keys)
        {
            if (keys == null || keys.Count() == 0) return EmptyTable;
            var result = Groups.Rows.Cast<DataRow>()
                                    .Where(row =>
                                    {
                                        return keys.Any(key => row["name"].ToString().ToLower().Contains(key));
                                    });
            if (result == null || result.Count() == 0) return EmptyTable;
            return result.CopyToDataTable();
        }
        DataTable SelectGroups(params string[] groupIds)
        {
            if (groupIds == null || groupIds.Count() == 0) return EmptyTable;
            var result = Groups.Rows.Cast<DataRow>()
                                    .Where(row => groupIds.Contains(row["id"].ToString()));
            if (result == null || result.Count() == 0) return EmptyTable;
            return result.CopyToDataTable();
        }
        DataTable SearchGroupDetailsOfGroupGridRow(int rowIndex)
        {
            if (grid_Groups.Rows.Count == 0 || rowIndex < 0 || rowIndex >= grid_Groups.RowCount) return EmptyTable;
            var groupId = grid_Groups.Rows[rowIndex].Cells["id"].Value.ToString();
            return SearchGroupDetails(groupId);
        }
        DataTable SearchGroupDetails(string groupId)
        {
            groupId = groupId.ToLower();
            var result = GroupDetails.Rows.Cast<DataRow>()
                                          .Where(row => row["group_id"].ToString().ToLower() == groupId);
            if (result == null || result.Count() == 0) return EmptyTable;
            return result.CopyToDataTable();
        }

        IEnumerable<DataRow> SearchStocksCrossGroups(IEnumerable<string> groupIds)
        {
            IEnumerable<DataRow> result = null;
            foreach (var groupId in groupIds)
            {
                //var groupId = gridRow.Cells["id"].Value.ToString();
                var rows = SearchGroupDetails(groupId);
                if (rows == null || rows.Rows.Count == 0) continue;
                if (result == null)
                {
                    result = rows.Rows.Cast<DataRow>();
                }
                else
                {
                    var intersected = result/*.Rows.Cast<DataRow>()*/.Intersect(rows.Rows.Cast<DataRow>(), new GroupDetailComparer());
                    if (intersected == null || intersected.Count() == 0)
                    {
                        result = null;
                        break;
                    }
                    else
                    {
                        result = intersected/*.CopyToDataTable()*/;
                    }
                }
            }
            return result;
        }

        void ShowGroupDetails(DataTable result)
        {
            if (result == null || result.Rows.Count == 0)
            {
                grid_Group_Details.DataSource = null;
                gbx_Group_Detail.Text = $"成分股";
            }
            else
            {
                grid_Group_Details.DataSource = result;
                gbx_Group_Detail.Text = $"成分股({result.Rows.Count})";
                grid_Group_Details.Columns[0].Visible = grid_Group_Details.Columns[1].Visible = grid_Group_Details.Columns[2].Visible = false;
            }
            //grid_Group_Details.Refresh();
            //grid_Group_Details.Update();
        }


        private void dgv_Stock_Result_CellMouseClick(object sender, DataGridViewCellMouseEventArgs e)
        {
            var srows = grid_Stock_Result.SelectedRows;
            if (srows == null || srows.Count == 0) return;
            ///查股票板块
            var stockCode = srows[0].Cells["code"].Value.ToString();
            var groupIds = GroupDetails.Rows.Cast<DataRow>()
                                            .Where(row => row["uid"].ToString().ToLower().Contains(stockCode))
                                            .Select(row => row["group_id"].ToString())
                                            .Distinct()
                                            .ToArray();
            if (groupIds == null || groupIds.Count() == 0)
            {
                grid_Groups.DataSource = null;
                ShowGroupDetails(null);
            }
            else
            {
                var groups = SelectGroups(groupIds);
                grid_Groups.DataSource = groups;
                ShowGroupDetails(SearchGroupDetails(groups.Rows[0]["id"].ToString()));
            }

        }

        private void dgv_Group_Details_CellDoubleClick(object sender, DataGridViewCellEventArgs e)
        {

        }

        private void tbx_Search_KeyPress(object sender, KeyPressEventArgs e)
        {
            if (e.KeyChar != (char)Keys.Enter) return;
            var key = tbx_Search.Text.Trim().ToLower();
            if (key == string.Empty)
            {
                Reset();
                return;
            }
            ///查股票
            var stocks = SearchStocks(key);
            ShowStocks(stocks);
        }

        private void grid_Group_Details_CellMouseClick(object sender, DataGridViewCellMouseEventArgs e)
        {
            var rowId = e.RowIndex;
            var colId = e.ColumnIndex;
            if (rowId < 0 || rowId >= grid_Group_Details.Rows.Count) return;
            var stockCode = grid_Group_Details.Rows[rowId].Cells["stock_code"].Value.ToString().ToLower();
            BrowerStockDetail(stockCode);
            var jg_zdf = Global.QueryStockRealtimeQuotes_THS(stockCode);
        }

        WebClient client = new WebClient();
        WebBrowser WBrower_Stock = new WebBrowser();
        void BrowerStockDetail(string stockCode)
        {
            var result = Stocks.Select($"code = {stockCode}");
            if (result == null || result.Count() == 0) return;
            var exc = ParseStockExchange(result.First()["exchange"].ToString());
            if (exc == null)
            {
                MessageBox.Show("股票交易所未知");
                return;
            }
            var uri = $"https://quote.eastmoney.com/{exc}{stockCode}.html";//https://quote.eastmoney.com/sh510230.html
            byte[] bytes = null;
            try
            {
                bytes = client.DownloadData(uri);
            }
            catch (Exception ex)
            {
                MessageBox.Show("Error:" + ex.Message);
                return;
            }
            var savePath = AppDomain.CurrentDomain.BaseDirectory + $@"StockPages\";
            if (!Directory.Exists(savePath))
            {
                try
                {
                    Directory.CreateDirectory(savePath);
                }
                catch { }
            }
            var stockName = result.First()["name"].ToString().Replace("*", "");
            ///TODO:勿删
            //File.WriteAllBytes($@"{savePath}{stockName}({stockCode}).html", bytes);
            string text2 = Encoding.GetEncoding("GB2312").GetString(bytes);
            Console.WriteLine(text2);
            WBrower_Stock.Url = new Uri(uri);
            if (!gbx_Brower.Controls.Contains(WBrower_Stock))
            {
                WBrower_Stock.ScriptErrorsSuppressed = false;
                gbx_Brower.Controls.Add(WBrower_Stock);
                WBrower_Stock.Dock = DockStyle.Fill;
                WBrower_Stock.Show();
            }
        }
        string ParseStockExchange(string exchange)
        {
            switch (exchange)
            {
                case "上海": return "sh";
                case "深圳": return "sz";
                default: return "sh";
            }
        }

        private void tbx_Stock_Result_KeyPress(object sender, KeyPressEventArgs e)
        {
            if (e.KeyChar != (char)Keys.Enter) return;
            var key = tbx_Search_Stock.Text.Trim().ToLower();
            if (key == string.Empty)
            {
                Reset();
                return;
            }
            ///查股票
            var stocks = SearchStocks(key);
            ShowStocks(stocks);
        }

        private void grid_Stock_Result_SelectionChanged(object sender, EventArgs e)
        {
            var srows = grid_Stock_Result.SelectedRows;
            if (srows == null || srows.Count == 0) return;
            ///查股票板块
            var stockCode = srows[0].Cells["code"].Value.ToString();
            var groupIds = GroupDetails.Rows.Cast<DataRow>()
                                            .Where(row => row["uid"].ToString().ToLower().Contains(stockCode))
                                            .Select(row => row["group_id"].ToString())
                                            .Distinct()
                                            .ToArray();
            if (groupIds == null || groupIds.Count() == 0)
            {
                grid_Groups.DataSource = null;
                ShowGroupDetails(null);
            }
            else
            {
                var groups = SelectGroups(groupIds);
                grid_Groups.DataSource = groups;
                ShowGroupDetails(SearchGroupDetails(groups.Rows[0]["id"].ToString()));
            }
        }

        private void tbx_Search_Bk_KeyPress(object sender, KeyPressEventArgs e)
        {
            if (e.KeyChar != (char)Keys.Enter) return;
            var key = tbx_Search_Bk.Text.Trim().ToLower();
            if (key == string.Empty)
            {
                Reset();
                return;
            }
            key = key.Replace(",", " ").Replace("，", " ");
            var isMulti = key.Contains(" ");
            DataTable groups;
            if (isMulti)
            {
                var keys = key.Split(' ');
                groups = SearchGroups(keys);
            }
            else
            {
                groups = SearchGroups(key);
            }
            if (groups == null) { Clear(); return; }
            grid_Groups.DataSource = groups;
            ShowGroupDetails(SearchGroupDetails(groups.Rows[0]["id"].ToString()));
        }

        //TODO:
        //1.展示前30板块
        //2.对股票结果进行筛选：市盈率>0&<30；
        Dictionary<string, string> Bks = new Dictionary<string, string>();
        Color Bk_BC_U = Color.FromName("Control");//FromArgb(64, 64, 200);
        Color Bk_BC_S = Color.FromArgb(32, 32, 100);
        List<Button> SelectedBkBtns = new List<Button>();
        List<string> SelectedBkIds_Btn = new List<string>();
        List<string> SelectedBkIds_Grid = new List<string>();
        void SelectedBkBtn(Button btn)
        {
            btn.BackColor = Bk_BC_S;
            btn.ForeColor = Color.White;
            if (!SelectedBkBtns.Contains(btn))
            {
                SelectedBkBtns.Add(btn);
            }
            var bkId = btn.Tag.ToString();
            if (!SelectedBkIds_Btn.Contains(bkId))
            {
                SelectedBkIds_Btn.Add(bkId);
            }
        }
        void UnselectedBkBtn(Button btn)
        {
            btn.BackColor = Bk_BC_U;
            btn.ForeColor = Color.Black;
            if (SelectedBkBtns.Contains(btn))
            {
                SelectedBkBtns.Remove(btn);
            }
            var bkId = btn.Tag.ToString();
            if (SelectedBkIds_Btn.Contains(bkId))
            {
                SelectedBkIds_Btn.Remove(bkId);
            }
        }
        int BkPageCapacity = 100;
        int BkPageIndex = 0;
        int BkPages = 0;
        bool LoadLocalBks(string localFile, out string err)
        {
            try
            {
                var bytes = File.ReadAllBytes(localFile);
                string content = Encoding.GetEncoding("GB2312").GetString(bytes);
                Console.WriteLine(content);
                var matchs = Regex.Matches(content, @"bk_\d\d\d\d\D*<");
                int index = 0;
                var matchs_rev = matchs.Cast<Match>().Reverse();
                foreach (Match match in matchs_rev)
                {
                    var subs = match.Value.Split('.');
                    var bkCode = subs[0];
                    var bkName = subs[1].Substring(23).Split('<')[0];
                    if (!Bks.ContainsKey(bkCode))
                    {
                        Bks.Add(bkCode, bkName);
                    }
                }
                err = null;
                return true;
            }
            catch (Exception ex)
            {
                err = ex.Message;
                return false;
            }
        }

        void ShowBkPage(int page)
        {
            if (page < 0 || page >= BkPages) return;
            fpn_Bks.Controls.Clear();
            var offset = page * BkPageCapacity;
            var bks = Bks.Skip(offset).Take(BkPageCapacity);
            foreach (var bk in bks)
            {
                var btn_Bk = new Button();
                btn_Bk.AutoSize = true;
                btn_Bk.Text = bk.Value;
                btn_Bk.Tag = bk.Key;
                UnselectedBkBtn(btn_Bk);
                btn_Bk.MouseClick += (o, e) =>
                {
                    var btn = (Button)o;
                    if (ModifierKeys == Keys.Shift || ModifierKeys == Keys.Control)
                    {
                        if (SelectedBkBtns.Contains(btn))
                        {
                            UnselectedBkBtn(btn);
                        }
                        else
                        {
                            SelectedBkBtn(btn);
                        }
                    }
                    else
                    {
                        var s_btns = SelectedBkBtns.Count;
                        for (int i = s_btns - 1; i >= 0; i--)
                        {
                            UnselectedBkBtn(SelectedBkBtns[i]);
                        }
                        SelectedBkBtn(btn);
                    }
                    var result = SearchStocksCrossGroups(SelectedBkIds_Btn.Union(SelectedBkIds_Grid));
                    ShowResultStocks(result);
                };
                fpn_Bks.Controls.Add(btn_Bk);
                btn_Bk.Show();
            }
            BkPageIndex = page;
            lb_BkPages.Text = $"{BkPageIndex + 1}/{BkPages}";
        }
        //IEnumerable<string> IntersectOf(IEnumerable<string> bks1, IEnumerable<string> bks2)
        //{
        //    if (bks1.Count() == 0) return bks2;
        //    if (bks2.Count() == 0) return bks1;
        //    return bks1.Union(bks2);
        //}

        private void btn_BkPage_Next_Click(object sender, EventArgs e)
        {
            ShowBkPage(++BkPageIndex);
        }

        private void btn_BkPage_Pre_Click(object sender, EventArgs e)
        {
            //低空，固态，人形机器人;
            ShowBkPage(--BkPageIndex);
        }
    }
}
